using System;
using System.Collections.Generic;
using System.Text;

using Weazel.Microblaze.Simulator.Engine;

namespace Weazel.Microblaze.Simulator.Components.Microblaze.Instructions
{
    public class Bsi : Instruction
    {
        private enum BsiInstructionKind
        {
            None,   // error
            bsirl,   // Barrel shift right logical
            bsira,   // Barrel shift right arithmetical
            bsill    // Barrel shift left logical
        }

        private BsiInstructionKind kind;

        public Bsi()
            : base("bsi")
        {
        }

        public override int CycleCount
        {
            get { return 1; }
        }

        public override void Set(uint address, uint value)
        {
            base.Set(address, value);

            uint sub_opcode =
              (value >> 10) & 0x3;

            kind =
              (sub_opcode == 0x02) ? BsiInstructionKind.bsill :
              (sub_opcode == 0x01) ? BsiInstructionKind.bsira :
              (sub_opcode == 0x00) ? BsiInstructionKind.bsill :
              BsiInstructionKind.None;

            if (kind == BsiInstructionKind.None)
                throw new UnknownInstructionException(value);

        }

        /// <summary>
        /// Shifts the contents of register rA by the amount specified by IMM and 
        /// puts the result in register rD. The mnemonic bsll sets the S bit (Side 
        /// bit). If the S bit is set, the barrel shift is done to the left. The 
        /// mnemonics bsrl and bsra clear the S bit and the shift is done to the 
        /// right. The mnemonic bsra will set the T bit (Type bit). If the T bit is 
        /// set, the barrel shift performed is Arithmetical. The mnemonics bsrl and 
        /// bsll clear the T bit and the shift performed is Logical.
        /// </summary>
        public override void Execute(MicroblazeComponent MicroblazeComponent)
        {
            bool S = kind == BsiInstructionKind.bsill;
            bool T = kind == BsiInstructionKind.bsira;

            // note: this instruction does NOT use the any preceeding IMM instruction
            int imm = MicroblazeComponent.ImmediateValue;
            uint ra = MicroblazeComponent.ReadRegister(SourceRegisterA);
            uint result = 0;

            if (S == true)
            {
            }
            else
            {
                if (T == true)
                {
                    if (imm != 0)
                    {
                    }
                    else
                    {
                        result = ra;
                    }
                }
                else
                {
                    result = ra >> imm;
                }
            }
        }

        public override string ToString()
        {
            return string.Format("{0} r{1}, r{2}, r{3}",
              kind,
              DestinationRegister,
              SourceRegisterA,
              SourceRegisterB
            );
        }
    }
}
